package com.pshcp.patient.api;

import com.external.common.WebServiceException;
import com.external.hospital.ap.UserApManager;
import com.external.service.WsRequestService;
import com.external.ws.soap.entity.dto.PatCardQueryDTO;
import com.external.ws.soap.entity.dto.UpdatePatInfoDTO;
import com.external.ws.soap.entity.res.CreatPatCardRes;
import com.external.ws.soap.entity.res.PatCard;
import com.external.ws.soap.entity.res.PatientCheckRes;
import com.framework.base.ResultBuilder;
import com.framework.base.ResultDTO;
import com.framework.exception.BizException;
import com.framework.logaop.Log;
import com.framework.logaop.LogSourceEnum;
import com.framework.logaop.LogTypeEnum;
import com.framework.thread.ReqComHold;
import com.framework.tool.CommonTool;
import com.framework.util.LocLockUtil;
import com.pshcp.common.enums.CardTypeEnum;
import com.pshcp.common.enums.CommonStatusEnum;
import com.pshcp.common.enums.PatCardTypeEnum;
import com.pshcp.domain.dto.PatientDTO;
import com.pshcp.domain.model.Patient;
import com.pshcp.domain.model.PatientQrcode;
import com.pshcp.domain.vo.PatientVO;
import com.pshcp.patient.domain.patient.ao.PatientAddAO;
import com.pshcp.patient.domain.patient.ao.PatientBindAO;
import com.pshcp.patient.domain.patient.ao.PatientDelAO;
import com.pshcp.patient.domain.patient.ao.PatientDetailAO;
import com.pshcp.patient.domain.patient.ao.PatientListAO;
import com.pshcp.patient.domain.patient.ao.PatientMedicalIntroAO;
import com.pshcp.patient.domain.patient.ao.PatientOnlineFilingAO;
import com.pshcp.patient.domain.patient.ao.PatientOnlineFilingValidAO;
import com.pshcp.patient.domain.patient.vo.PatientListVO;
import com.pshcp.patient.domain.patient.vo.PatientPubListVO;
import com.pshcp.patient.tool.PatientTools;
import com.pshcp.service.PatientService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.List;

@Api(tags = {"患者端-就诊人"})
@Slf4j
@RestController
@RequestMapping("/api/patient/patient")
public class PatientAPI {

    @Autowired
    private WsRequestService wsRequestService;

    @Autowired
    private PatientService patientService;

    @Autowired
    private UserApManager userApManager;

    @ApiOperation("就诊人列表")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "就诊人列表")
    @PostMapping("/list")
    public ResultDTO<List<PatientListVO>> list(@RequestBody PatientListAO patientListAO) {
        PatientDTO patient = new PatientDTO();
        patient.setPatientUserId(ReqComHold.getReqCom().getUserId());
        patient.setStatus(CommonStatusEnum.INIT.getCode());
        patient.setOnlyBindHis(patientListAO.isOnlyBindHis());
        List<Patient> patients = patientService.list(patient);
        return ResultBuilder.success(CommonTool.copyPropertiesList(patients, PatientListVO.class));
    }

    @ApiOperation("生成就诊卡二维码")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "生成就诊卡二维码")
    @PostMapping("/createQrCode")
    public ResultDTO<Object> createQrCode(@RequestBody PatientBindAO patientBindAO) throws BizException{
        CommonTool.checkObj(patientBindAO.getPatientCardNo(), "90000006");
        PatientQrcode PatientQrcode = patientService.createQrCode(patientBindAO.getPatientCardNo());
        return ResultBuilder.success(PatientQrcode);
    }

    @ApiOperation("就诊人列表（未脱敏）")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "就诊人列表（未脱敏）")
    @PostMapping("/listPub")
    public ResultDTO<List<PatientPubListVO>> listPub(@RequestBody PatientListAO patientListAO) {
        PatientDTO patient = new PatientDTO();
        patient.setPatientUserId(ReqComHold.getReqCom().getUserId());
        patient.setStatus(CommonStatusEnum.INIT.getCode());
        patient.setOnlyBindHis(patientListAO.isOnlyBindHis());
        List<Patient> patients = patientService.list(patient);
        return ResultBuilder.success(CommonTool.copyPropertiesList(patients, PatientPubListVO.class));
    }

    @ApiOperation("更新患者最后操作时间")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.UPDATE, desc = "更新患者最后操作时间")
    @PostMapping("/updatePatientLastHandleTime")
    public ResultDTO<Object> updatePatientLastHandleTime() {
        // 修改用户患者最后登录时间
        Long patientUserId = ReqComHold.getReqCom().getUserId();
        patientService.updatePatientLastHandleTime(patientUserId);
        return ResultBuilder.success();
    }

    @ApiOperation("就诊人详情")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "就诊人详情")
    @PostMapping("/detail")
    public ResultDTO<PatientVO> detail(@RequestBody PatientDetailAO detailAO) {

        Patient patient = patientService.findById(detailAO.getPatientId());

        return ResultBuilder.success(CommonTool.copyProperties(patient, PatientVO.class));
    }

    @ApiOperation("新增/修改就诊人")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.ADD, desc = "新增/修改就诊人")
    @PostMapping("/addOrUpdate")
    public ResultDTO addOrUpdate(@RequestBody PatientAddAO patientAddAO) throws BizException {
        String lockKey = LocLockUtil.buildKey("addOrUpdatePatient");
        LocLockUtil.lock(lockKey);
        Patient patientDb;
        try {
            if (!ObjectUtils.isEmpty(patientAddAO.getIdCardNo())) {
                List<Patient> patients = findIdCard(patientAddAO.getIdCardType(), patientAddAO.getIdCardNo());
                if(!CollectionUtils.isEmpty(patients)
                        && !patients.get(0).getId().equals(patientAddAO.getPatientId())){
                    throw new BizException("10150001");
                }
            }
            patientDb = PatientTools.buildAddAO2Model(patientAddAO);
            patientDb.setLastHandleTime(new Date());
            if (patientAddAO.getPatientId() != null) {
                patientDb.setId(patientAddAO.getPatientId());
                patientService.update(patientDb);
            } else {
                buildHisCardInfo(patientAddAO, patientDb);
                patientService.insert(patientDb);
            }
            if (patientDb.getIsDefault() != null && patientDb.getIsDefault().intValue() == 1) {
                patientService.updateDefault(patientDb.getPatientUserId(), patientDb.getId());
            }
        }finally {
            LocLockUtil.unLock(lockKey);
        }
        //sync to platform
        Patient entity = patientService.findById(patientDb.getId());
        userApManager.savePatientInquirer(entity);
        return ResultBuilder.success(patientDb.getId());
    }

    private List<Patient> findIdCard(Integer idCardType, String idCardNo) throws BizException {
        Patient params = new Patient();
        params.setPatientUserId(ReqComHold.getReqCom().getUserId());
        params.setIdCardType(idCardType);
        params.setIdCardNo(idCardNo);
        params.setStatus(CommonStatusEnum.INIT.getCode());
        List<Patient> patients = patientService.select(params);
        return patients;
    }

    private void buildHisCardInfo(PatientAddAO patientAddAO,Patient patientDb) throws WebServiceException {
        PatCardQueryDTO dto = new PatCardQueryDTO();
        CardTypeEnum cardTypeEnum = CardTypeEnum.getByCode(patientAddAO.getIdCardType());
        dto.setIdCardType(cardTypeEnum == null ? "": cardTypeEnum.getHisCode());
        dto.setIdCardNo(patientAddAO.getIdCardNo());
        List<PatCard> patCards = wsRequestService.patCardQuery(dto);
        if(CollectionUtils.isEmpty(patCards)){
            return;
        }
        PatCard patCard = patCards.get(0);
        patientDb.setHisPatientId(patCard.getAccessPatId());
        patientDb.setPatientCardNo(patCard.getPatCardNo());
        if(!ObjectUtils.isEmpty(patCard.getPatCardType())){
            patientDb.setPatientCardType(0);
        }

    }

    @ApiOperation("就诊人删除")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.LOGIC_DEL, desc = "就诊人删除")
    @PostMapping("/del")
    public ResultDTO del(@RequestBody PatientDelAO delAO) {
        patientService.delById(delAO.getPatientId());
        //sync to platform
        Patient patient = patientService.findById(delAO.getPatientId());
        userApManager.deletePatientInquirer(patient);
        return ResultBuilder.success();
    }

    @ApiOperation("就诊人绑卡")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.UPDATE, desc = "就诊人绑卡")
    @PostMapping("/bindCardNo")
    public ResultDTO bindCardNo(@RequestBody PatientBindAO patientBindAO) throws BizException {
        Patient patient = patientService.findById(patientBindAO.getPatientId());
        CommonTool.checkObj(patient, "10120002");
        // search ws validate cardNo
        patient.setPatientCardType(PatCardTypeEnum.PAT_VISIT_CARD.getCode());
        patient.setPatientCardNo(patientBindAO.getPatientCardNo());
        PatientCheckRes checkRes = wsRequestService.patientCheck(PatientTools.buildWsCheckPatientDTO(patient));
        //update his info
        patient.setHisPatientId(checkRes.getAccessPatId());
        //update to patient db
        patientService.update(patient);
        return ResultBuilder.success();
    }

    @ApiOperation("在线建档验证")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "在线建档验证")
    @PostMapping("/onlineFilingValid")
    public ResultDTO onlineFilingValid(@RequestBody PatientOnlineFilingValidAO onlineFilingValidAO) throws BizException {
        List<PatCard> patCards = patCardQuery(onlineFilingValidAO.getIdCardType(), onlineFilingValidAO.getIdCardNo());
        if(CollectionUtils.isEmpty(patCards)){
            return ResultBuilder.success();
        }
        return ResultBuilder.failure("10150003");
    }

    private List<PatCard> patCardQuery(Integer idCardType, String idCardNo) throws WebServiceException {
        PatCardQueryDTO dto = new PatCardQueryDTO();
        CardTypeEnum cardTypeEnum = CardTypeEnum.getByCode(idCardType);
        dto.setIdCardType(cardTypeEnum == null ? "": cardTypeEnum.getHisCode());
        dto.setIdCardNo(idCardNo);
        List<PatCard> patCards = wsRequestService.patCardQuery(dto);
        return patCards;
    }

    @ApiOperation("在线建档")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.ADD, desc = "在线建档")
    @PostMapping("/onlineFiling")
    public ResultDTO onlineFiling(@RequestBody PatientOnlineFilingAO onlineFilingAO) throws BizException {
        String lockKey = LocLockUtil.buildKey("onlineFiling");
        try {
            LocLockUtil.lock(lockKey);
            if(!ObjectUtils.isEmpty(onlineFilingAO.getPatientId())){
                Patient patient = patientService.findById(onlineFilingAO.getPatientId());
                onlineFilingAO.setIdCardNo(patient.getIdCardNo());
                onlineFilingAO.setPhone(patient.getPhone());
            }
            if (!ObjectUtils.isEmpty(onlineFilingAO.getIdCardNo())) {
                List<PatCard> patCards = patCardQuery(onlineFilingAO.getIdCardType(), onlineFilingAO.getIdCardNo());
                if(!CollectionUtils.isEmpty(patCards)){
                    // 如果已经建档 直接添加就诊人
                    Patient patient = PatientTools.buildFilingAO2Model(onlineFilingAO);
                    patient.setHisPatientId(patCards.get(0).getAccessPatId());
                    patient.setPatientCardNo(patCards.get(0).getPatCardNo());
                    List<Patient> patients = findIdCard(onlineFilingAO.getIdCardType(), onlineFilingAO.getIdCardNo());
                    if(!CollectionUtils.isEmpty(patients)){
                        patient.setId(patients.get(0).getId());
                    }
                    // 处理时间
                    patient.setLastHandleTime(new Date());
                    //update db
                    if (patient.getId() != null) {
                        patientService.update(patient);
                    } else {
                        patientService.insert(patient);
                    }
                    return ResultBuilder.success();
                }
            }
            // call ws update
            CreatPatCardRes patCardRes = wsRequestService.creatPatCard(PatientTools.buildWsCreatePatCardDTO(onlineFilingAO));
            Patient patient = PatientTools.buildFilingAO2Model(onlineFilingAO);
            PatientTools.buildWsCreatePatCardResDTO(patient, patCardRes);
            // find patient by db
            List<Patient> patients = findIdCard(onlineFilingAO.getIdCardType(), onlineFilingAO.getIdCardNo());
            if(!CollectionUtils.isEmpty(patients)){
                patient.setId(patients.get(0).getId());
            }
            // 处理时间
            patient.setLastHandleTime(new Date());
            //update db
            if (patient.getId() != null) {
                patientService.update(patient);
            } else {
                patientService.insert(patient);
            }
        }finally {
            LocLockUtil.unLock(lockKey);
        }
        return ResultBuilder.success();
    }

    @ApiOperation("病案补录")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.UPDATE, desc = "病案补录")
    @PostMapping("/addMedicalIntro")
    public ResultDTO addMedicalIntro(@RequestBody PatientMedicalIntroAO patientMedicalIntroAO) throws BizException {
        Patient patient = patientService.findById(patientMedicalIntroAO.getPatientId());
        CommonTool.checkObj(patient, "10120002");
        CommonTool.checkObj(patient.getHisPatientId(), "10150002");
        // call ws update
        UpdatePatInfoDTO patInfoDTO = PatientTools.buildWsUpdatePatDTO(patient, patientMedicalIntroAO);
        wsRequestService.updatePatInfo(patInfoDTO);
        //update db
        patientService.update(PatientTools.buildIntroAO2Model(patientMedicalIntroAO));

        return ResultBuilder.success();
    }

}
